/*
 * Copyright (C) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef IMAGE_KNIFE_C_KEKE_IMAGEKNIFE_REQUEST_INTERNAL_H
#define IMAGE_KNIFE_C_KEKE_IMAGEKNIFE_REQUEST_INTERNAL_H

#include "imageknife_node.h"
#include "imageknife_request.h"
#include "log.h"
#include "promise/promise.h"
#include <mutex>

namespace ImageKnifePro {

class ImageKnifeRequestInternal : public ImageKnifeRequest {
public:
    enum class PreloadType {
        // 非preload请求
        NONE = 0,
        // 普通preload请求
        PRELOAD,
        // preloadCache，获取文件缓存路径的请求
        PRELOAD_FILE,
        // getCacheImage, 获取pixelmap的请求
        PRELOAD_PIXEL
    };

    void SetImageNode(std::weak_ptr<ImageKnifeNode> node);
    std::shared_ptr<ImageKnifeNode> GetImageNode() const;
    void InsertTask(std::shared_ptr<ImageKnifeTask> task, ImageRequestType type);

    std::shared_ptr<ImageKnifeTask> GetTask(ImageRequestType type);

    void RemoveTask(ImageRequestType type);

    void MarkStatusComplete();

    void MarkStatusError();

    bool MarkExecuted();
    bool MarkMainSrcEnqueued();

    void SyncLoad(bool syncLoad);

    void Destroy();

    bool IsMainSrcComplete() const;

    bool IsDestroy() const;

    bool IsSyncLoad() const;

    std::string GetNodeId() const;

    int GetVersion() const;

    Status GetStatus() const override;

    std::shared_ptr<ImageKnifeOption> GetImageKnifeOption() const override;

    bool IsPreload() const;

    bool IsPreloadAnimator() const;

    bool IsMemoryCacheSkiped() const;

    bool IsFileCacheSkiped() const;

    void SetAnimator(bool animator);

    void SetEnv(napi_env env);

    void SetJsRequestRef(napi_ref jsRequestRef);

    void SetComponentId(std::string componentId)
    {
        componentId_ = componentId;
    }

    void SetComponentSize(Image_Size imageSize);
    Image_Size GetRequestImageSize();

    ImageInfo &GetImageInfo();

    void ToggleReQueue();
    bool IsRequeue();

    void GetPixelMapInfo(std::shared_ptr<ImageData> imageData);

    // 用于重试加载
    std::string GetRequestId() const;

    std::shared_ptr<Promise<std::string>> GetFilePathPromise() const;

    bool IsPreloadCache() const;

    void ResolvePromiseFilePath(std::string filePath);
    void ResolvePromiseImageData(std::shared_ptr<ImageData> imageData);
    void ResolvePromiseImageData(std::shared_ptr<ImageDataCache> imageDataCache);
    void ResolveFailedPromises(ImageRequestType type);
    bool TryResolvePromiseFilePath(std::string filePath);
    bool TryResolvePromiseImageData(std::shared_ptr<ImageData> imageData);

    void MarkThumbnailSrcReady();
    void MarkThumbnailSrcUnavailable();
    bool IsThumbnailSrcReady() const;
    bool IsThumbnailSrcUnavailable() const;
    PreloadType GetPreloadType() const;

    ImageKnifeRequestInternal(std::shared_ptr<ImageKnifeOption> option, int componentVersion)
        : imageKnifeOption_(option), componentVersion_(componentVersion)
    {
        IMAGE_KNIFE_CHECK(option == nullptr);
        imageInfo_.customData = option->customData;
    }

    explicit ImageKnifeRequestInternal(std::shared_ptr<ImageKnifeOption> option)
        : imageKnifeOption_(option), preloadType_(PreloadType::PRELOAD)
    {
        static std::atomic<size_t> count = 0;
        componentId_ = "Preload_" + std::to_string(count);
        count++;
        IMAGE_KNIFE_CHECK(option == nullptr);
        imageInfo_.customData = option->customData;
    }

    ImageKnifeRequestInternal(std::shared_ptr<ImageKnifeOption> option, std::shared_ptr<Promise<std::string>> promise)
        : ImageKnifeRequestInternal(option)
    {
        // preloadCache 请求, 因需要固定返回文件缓存路径，跳过内存缓存读阶段
        cacheType_ = CacheStrategy::FILE;
        promiseFilePath_ = promise;
        componentId_ += "_Cache";
        preloadType_ = PreloadType::PRELOAD_FILE;
    }

    ImageKnifeRequestInternal(std::shared_ptr<ImageKnifeOption> option, CacheStrategy cacheType,
        std::shared_ptr<Promise<std::shared_ptr<ImageData>>> promise) : ImageKnifeRequestInternal(option)
    {
        // getImageCache 请求
        cacheType_ = cacheType;
        promiseImageData_ = promise;
        componentId_ += "_GetCache";
        preloadType_ = PreloadType::PRELOAD_PIXEL;
    }

    ~ImageKnifeRequestInternal() override
    {
        if (IsPreload() && jsRequestRef_ != nullptr) {
            ReleaseRefThreadSafe();
        }

        if (promiseFilePath_ != nullptr && !promiseFilePath_->IsResolved()) {
            promiseFilePath_->Resolve(std::string());
        }

        if (promiseImageData_ != nullptr && !promiseImageData_->IsResolved()) {
            promiseImageData_->Resolve(nullptr);
        }
    }

private:
    enum class ThumbnailStatus {
        PROGRESS, // 初始状态，加载中
        COMPLETE, // 加载成功
        UNAVAILABLE // 未使用thumbnail或加载失败
    };
    ThumbnailStatus thumbnailStatus_ = ThumbnailStatus::PROGRESS;

    std::weak_ptr<ImageKnifeNode> imageNode_;

    ImageInfo imageInfo_;
    Status status_ = Status::PROGRESS;
    std::shared_ptr<ImageKnifeOption> imageKnifeOption_ = nullptr;
    std::string componentId_;
    ArkUI_NodeHandle handle_ = nullptr;
    int componentVersion_ = -1;
    bool syncLoad_ = false;
    // 期望该请求以动图的方式处理，对preload类型的请求有效
    bool animator_ = false;
    // 标记请求是否下发执行过， 一个请求应只执行一次
    bool executed_ = false;
    // 标记主图是否已经入队执行过，一个请求应只执行一次
    bool mainSrcEnqueued_ = false;
    std::unordered_map<ImageRequestType, std::weak_ptr<ImageKnifeTask>> taskMap_;
    std::mutex taskMapLock_;

    // 读缓存策略，不同于option的写缓存策略
    CacheStrategy cacheType_ =  CacheStrategy::DEFAULT;
    std::shared_ptr<Promise<std::string>> promiseFilePath_ = nullptr;
    std::shared_ptr<Promise<std::shared_ptr<ImageData>>> promiseImageData_ = nullptr;
    // 由组件测算尺寸计算的图片请求尺寸
    Image_Size requestImageSize_ = {.width = 0, .height = 0};

    // 判断是否为Preload请求，预加载请求不进行显示
    PreloadType preloadType_ = PreloadType::NONE;
    napi_env env_ = nullptr;
    napi_ref jsRequestRef_ = nullptr;

    // 判断是否重新排队
    bool reQueue_ = false;

    void ReleaseRefThreadSafe();
};

} // end of namespace

#endif // IMAGE_KNIFE_C_KEKE_IMAGEKNIFE_REQUEST_INTERNAL_H
